﻿using System;
using static CyberU;
using static CyberU.UI;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections.Generic;
using TMPro;
using Unity.Properties;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine.Serialization;
using UnityEngine.EventSystems;

public class GraphNode : RectComponent
{
    public void RefreshTitlePosition(bool isEmpty)
    {
        if (isEmpty)
        {
            Delog("empty",ScenePath(gameObject),contentInputer.text);
            SetYOffset(titleInputer, 0);
            titleInputer.height = size * 1.6f;
            // Deloga(size, size * 1.6f);
            // Deloga(titleInputer.height);
        }
        else
        {
            // Delog("not empty",ScenePath(gameObject));
            titleInputer.height = size * 0.8f;
            // Delogc(titleInputer.height);
            SetYOffset(titleInputer, titleInputer.height/2);
            // Deloga(titleInputer.height);
        }
    }

    public Graph graph;

    public string id
    {
        get => data.id;
        set => data.id = value;
    }

    public bool isAddingLink;

    public bool _selected;

    public bool selected
    {
        get { return _selected; }
        set
        {
            if (value != _selected)
            {
                temporarilyPinned = temporarilyPinned;
                if (value)
                {
                    image.material = SelectedMaterial;
                }
                else
                {
                    image.material = UnSelectedMaterial;
                }

                SetActiveGameObject(addChild, value);
                SetActiveGameObject(deleteNode, value);
                SetActiveGameObject(deleteEdges, value);
                SetActiveGameObject(addLink, value);
            }

            _selected = value;
        }
    }

    public Image image;
    MouseOver mouseOver;
    MouseDown mouseDown;
    Clicker clicker;

    public GraphNodeData _data;

    public GraphNodeData data
    {
        get { return _data; }
        set
        {
            _data = value;
            UpdateFromData(value);
        }
    }

    public bool pinned
    {
        get
        {
            return Used(data) ? data.pinned : false;
        }
        set
        {
            if (Used((data)))
            {
                data.pinned = value;
            }
        }
    }

    public bool _temporarilyPinned;

    public bool temporarilyPinned
    {
        get { return pinned || selected || mouseOver.isMouseOver; }
        set
        {
            if (temporarilyPinned != _temporarilyPinned)
            {
                // Delog($"{Used(rigidbody)}");
                rigidbody.bodyType = (temporarilyPinned ? RigidbodyType2D.Static : RigidbodyType2D.Dynamic);
            }

            _temporarilyPinned = temporarilyPinned;
        }
    }

    public AddChild addChild;
    public DeleteNode deleteNode;
    public DeleteEdges deleteEdges;
    public AddLink addLink;
    public TextInput contentInputer;
    public TextInput titleInputer;

    public TextInput titleTextComponent
    {
        get => titleInputer;
        set => titleInputer = value;
    }

    public TextInput contentTextComponent
    {
        get => contentInputer;
        set => contentInputer = value;
    }

    public Rigidbody2D rigidbody;
    public CircleCollider2D collider;
    public DraggableUI draggable;

    public Color _color = defaultColor;
    public static Color defaultColor = new Color(205 / 225f, 81 / 225f, 10 / 225f, 1);

    public Color color
    {
        get { return _color; }
        set
        {
            _color = value;
            image.color = _color;
        }
    }


    public float size
    {
        get => radius;
        set { radius = value; }
    }

    public float scale
    {
        get { return size; }
        set { size = value; }
    }

    public float radius
    {
        set
        {
            collider.radius = value;
            data.size = value;
        }
        get { return data.size; }
    }

    public void Start()
    {
        radius = defaultSize;
        data.position = data._position;
        temporarilyPinned = temporarilyPinned;
        // Delog(data.position,data.node);
    }

    public Material SelectedMaterial;
    public Material UnSelectedMaterial;

    public void UpdateMaterial()
    {
        SelectedMaterial = LoadMaterial("CircleOutlined");
        UnSelectedMaterial = LoadMaterial("Circle");
    }

    public GameObject titleGameObject;
    public GameObject contentGameObject;
    public static float defaultSize = 50f;

    public void Awake()
    {
        base.Awake();
        // Delog($"{gameObject ==null}");
        UpdateMaterial();
        image = GetOrAddComponent<Image>(gameObject);
        // Delog($"{GetGameObject(name:"Title",parent: gameObject)==null}");
        titleGameObject = GetGameObject(name: "Title", parent: gameObject);
        contentGameObject = GetGameObject(name: "Content", parent: gameObject);
        titleInputer = GetOrAddComponent<TextInput>(titleGameObject);
        contentInputer = GetOrAddComponent<TextInput>(contentGameObject);
        titleInputer.defaultText = "";
        contentInputer.defaultText = "";
        titleInputer.Awake();
        contentInputer.Awake();
        // Deloga(titleInputer.textInput);
        GetOrAddComponent<ConstrainedText>(titleInputer.binedTextComponent);
        // Delog($"{title.textComponent == null}");
        GetOrAddComponent<ConstrainedText>(contentInputer.binedTextComponent).maxFontSize=16f;
        titleTextComponent.color = Color.white;
        contentTextComponent.color = Color.white;
        // Deloga(contentTextComponent.text);
        contentTextComponent.AddEmptyListener(isEmpty => { RefreshTitlePosition(isEmpty); });

        // Delog(content);
        rigidbody = GetOrAddComponent<Rigidbody2D>(gameObject);
        collider = GetOrAddComponent<CircleCollider2D>(gameObject);
        draggable = GetOrAddComponent<DraggableUI>(gameObject);
        // content.textComponent.alignment = TextAnchor.MiddleCenter;
        // Delog("init graphNode");
        // Delog($"has awakened. {title.textComponent==null}");

        mouseOver = GetOrAddComponent<MouseOver>(gameObject);
        mouseDown = GetOrAddComponent<MouseDown>(gameObject);
        mouseOver.AddToggle(() => temporarilyPinned = !temporarilyPinned);
        clicker = GetOrAddComponent<Clicker>(gameObject);
        clicker.AddDouble(() =>
        {
            if (selected)
            {
                graph.SelectNode(null);
            }
            else
            {
                graph.SelectNode(this);
            }
        });
        clicker.Add(() =>
        {
            // Delog("clicked1");
            if (graph.isAddingLink)
            {
                graph.isAddingLink = false;
                graph.AddEdge(from: graph.selectedNode, to: this);
            }
            else
            {
                pinned = !pinned;
                // Deloga("chage pinned",pinned);
            }
        });
        temporarilyPinned = pinned;

        addChild = FindInChild<AddChild>(gameObject);
        deleteNode = FindInChild<DeleteNode>(gameObject);
        addLink = FindInChild<AddLink>(gameObject);
        deleteEdges = FindInChild<DeleteEdges>(gameObject);
        DeactiveGameObject(addChild);
        DeactiveGameObject(addLink);
        DeactiveGameObject(deleteNode);
        DeactiveGameObject(deleteEdges);
        // addChild.gameObject.SetActive(false);
    }

    void Update()
    {
        OnWheelScale();
    }

    void OnWheelScale()
    {
        if (scrollLock.Acquire(MousePriority.Component))
        {
            float scroll = Input.GetAxis("Mouse ScrollWheel");
            if (scroll != 0)
            {
                size += scroll;
            }

            scrollLock.Release(MousePriority.Component);
        }
    }

    public string title
    {
        get { return titleInputer.text; }
        set { titleInputer.text = value; }
    }

    public string name
    {
        get => title;
        set => title = value;
    }

    public string content
    {
        get => text;
        set => text = value;
    }

    public string description
    {
        get => text;
        set => text = value;
    }

    public void UpdateFromData(GraphNodeData data_)
    {
        // Deloge("Loading from data ...");
        data.id = data_.id;
        name = ClarifiedStr(data_.name);
        pinned = data_.pinned;
        size = data_.size != 0 ? data_.size : size;
        text = ClarifiedStr(data_.description);
        color = data_.color != null ? data_.color : defaultColor;
        UpdateTextPosition();
        // nodeNameText.fontSize = 12;
        // Delogc(titleInputer.textComponent.text);
    }

    public string text
    {
        set
        {
            contentTextComponent.text = value;
            // Delogc(value);
        }
        get { return contentTextComponent.text; }
    }

    public void UpdateTextPosition()
    {
        float titleDownOffset = (string.IsNullOrEmpty(contentTextComponent.text)) ? -titleTextComponent.height / 2f : 0;
        titleTextComponent.rectTransform.anchoredPosition = new Vector2(contentTextComponent.rectTransform.anchoredPosition.x, titleDownOffset + titleTextComponent.height / 2f);
        contentTextComponent.rectTransform.anchoredPosition = new Vector2(contentTextComponent.rectTransform.anchoredPosition.x, -contentTextComponent.height / 2f);
    }
}

public class GraphNodeData
{
    [Newtonsoft.Json.JsonIgnore] public SerializableVector2 _position;
    public GraphNode node;
    public SerializableVector2 position
    {
        get
        {
            if (Used(node))
            {
                return AsRectTransform(node).anchoredPosition;
            }
            else
            {
                return _position;
            }
        }
        set
        {
            if (!Used(value))
            {
                return;
            }
            if (Enabled(node))
            {
                // Deloga(AsRectTransform(node).anchoredPosition,value);
                AsRectTransform(node).anchoredPosition = value;
            }
            else
            {
                _position = value;
            }
        }
    }

    [Newtonsoft.Json.JsonProperty("id")] public string _id;

    [Newtonsoft.Json.JsonIgnore]
    public string id
    {
        get
        {
            if (Used(_id))
            {
                return _id;
            }

            if (!Used(node))
            {
                return "";
            }

            if (string.IsNullOrEmpty(_id))
            {
                return $"{node.graph.n + 1}";
            }

            return _id;
        }
        set { _id = value; }
    }

    public void UpdateFromNode()
    {
        name = ClarifiedStr(node.name);
        description = ClarifiedStr(node.description);
    }

    public string name;
    public string description;
    public bool pinned;
    public float size;
    public SerializableColor serializableColor = new SerializableColor();

    [Newtonsoft.Json.JsonIgnore]
    public Color color
    {
        get { return serializableColor.ToColor(); }
        set { serializableColor.FromColor(value); }
    }

    public enum shape
    {
        circle,
        triangle,
        rectangle
    }

    // [Newtonsoft.Json.JsonIgnore]
    public GraphNodeData()
    {
        name = "unamed";
        color = GraphNode.defaultColor;
    }

    public GraphNodeData(GraphNode node)
    {
        this.node = node;
        // Delog($"{node.gameObject == null}");
    }
}